using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace BrokerClient
{
    [AttributeUsage(AttributeTargets.Class)]
    public class ActionControllerAttribute : Attribute
    {
        public int Cmd { get; }
        public ActionControllerAttribute(int cmd) => Cmd = cmd;
    }

    [AttributeUsage(AttributeTargets.Method)]
    public class ActionAttribute : Attribute
    {
        public int Act { get; }
        public ActionAttribute(int act) => Act = act;
    }

    public class ActionManager
    {
        private class ActionDescriptor
        {
            public MethodInfo Method;
            public object ControllerInstance;
            public ParameterInfo[] Parameters;
        }

        private readonly ConcurrentDictionary<(int cmd, int act), ActionDescriptor> _actions = new();

        public ActionManager()
        {
            ScanControllers();
        }

        private void ScanControllers()
        {
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes())
                .Where(t => t.GetCustomAttribute<ActionControllerAttribute>() != null);
            foreach (var type in types)
            {
                var ctrlAttr = type.GetCustomAttribute<ActionControllerAttribute>();
                var instance = Activator.CreateInstance(type);
                foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
                {
                    var actAttr = method.GetCustomAttribute<ActionAttribute>();
                    if (actAttr != null)
                    {
                        var desc = new ActionDescriptor
                        {
                            Method = method,
                            ControllerInstance = instance,
                            Parameters = method.GetParameters()
                        };
                        _actions[(ctrlAttr.Cmd, actAttr.Act)] = desc;
                    }
                }
            }
        }

        public object Invoke(int cmd, int act, params object[] args)
        {
            if (!_actions.TryGetValue((cmd, act), out var desc))
                throw new Exception($"No action found for cmd={cmd}, act={act}");
            var parameters = desc.Parameters;
            if ((args?.Length ?? 0) != parameters.Length)
                throw new ArgumentException($"Argument count mismatch for action cmd={cmd}, act={act}");
            var realArgs = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                var paramType = parameters[i].ParameterType;
                if (args[i] == null || paramType.IsInstanceOfType(args[i]))
                {
                    realArgs[i] = args[i];
                }
                else if (args[i] is byte[] bytes)
                {
                    // 支持MessagePack反序列化
                    //realArgs[i] = MessagePackSerializer.Deserialize(paramType, bytes);
                }
                else
                {
                    realArgs[i] = Convert.ChangeType(args[i], paramType);
                }
            }
            return desc.Method.Invoke(desc.ControllerInstance, realArgs);
        }
    }
} 